const promisedToTask = require("folktale/conversions/promised-to-task");
const { assignAll } = require("lodash/fp");

const PENDING = "pending"; //等待
const FULFILLED = "fulfilled"; //成功
const REJECTED = "rejected"; //失败

/* 
    判断是否是函数
    @return {boolean}
*/
const isFunction = (fn) => typeof fn === "function";

/* 
    判断函数有效性并执行函数
*/
const execFunction = (fn, ...args) => {
    if (isFunction(fn)) {
        return fn(...args);
    }
};

/* 
    循环调用callback
*/
const mapCallback = (fnArr, data) => {
    if (!Array.isArray(fnArr)) return;
    while (fnArr.length !== 0) {
        execFunction(fnArr.shift(), data);
    }
};

/* 
    解析promise
*/
const resolvePromise = (promise2, x, resolve, reject) => {
    if (promise2 === x) {
        return execFunction(reject, new TypeError("Chain Error"));
    } else if (x instanceof MyPromise) {
        x.then(
            (value) => execFunction(resolve, value),
            (reason) => execFunction(reject, reason)
        );
    } else {
        resolve(x);
    }
};

class MyPromise {
    constructor(executor) {
        try {
            executor(this.resolve, this.reject);
        } catch (e) {
            execFunction(this.reject, e);
        }
    }

    //promise的状态
    _status = PENDING;
    //成功之后的值
    data = undefined;
    //失败的原因
    resoan = undefined;
    //成功回调
    successCb = [];
    //失败回调
    failCb = [];

    get status() {
        return this._status;
    }

    //当非pending状态时，不可以修改状态
    set status(value) {
        if (this._status !== PENDING) return;
        if (value === PENDING) return;

        this._status = value;
    }

    resolve = (value) => {
        this.status = FULFILLED;
        this.data = value;
        mapCallback(this.successCb, this.data);
    };

    reject = (resoan) => {
        this.status = REJECTED;
        this.resoan = resoan;
        mapCallback(this.failCb, this.resoan);
    };

    catch = (failCallback) => {
        return this.then(undefined, failCallback);
    };

    finally = (callback) => {
        return this.then(
            (value) => {
                callback();
                return value;
            },
            (reason) => {
                callback();
                throw reason;
            }
        );
    };

    then(success = (value) => value, fail = (reason) => reason) {
        let promise2 = new MyPromise((resolve, reject) => {
            if (this._status === FULFILLED) {
                //链式调用
                //当返回值是普通值的时候，正常执行
                //当返回值是promise对象的时候，调用promise对象的then方法，传递promise的状态
                //异步，为了延迟执行
                setTimeout(() => {
                    try {
                        resolvePromise(
                            promise2,
                            execFunction(success, this.data),
                            resolve,
                            reject
                        );
                    } catch (e) {
                        execFunction(reject, e);
                    }
                }, 0);
            } else if (this._status === REJECTED) {
                setTimeout(() => {
                    try {
                        resolvePromise(
                            promise2,
                            execFunction(fail, this.resoan),
                            resolve,
                            reject
                        );
                    } catch (e) {
                        execFunction(reject, e);
                    }
                }, 0);
            } else {
                //处理等待状态
                this.successCb.push(() => {
                    setTimeout(() => {
                        try {
                            resolvePromise(
                                promise2,
                                execFunction(success, this.data),
                                resolve,
                                reject
                            );
                        } catch (e) {
                            execFunction(reject, e);
                        }
                    }, 0);
                });
                this.failCb.push(() => {
                    setTimeout(() => {
                        try {
                            resolvePromise(
                                promise2,
                                execFunction(fail, this.resoan),
                                resolve,
                                reject
                            );
                        } catch (e) {
                            execFunction(reject, e);
                        }
                    }, 0);
                });
            }
        });

        return promise2;
    }

    //实现all 方法
    static all(arr) {
        let results = [];

        return new MyPromise((resolve, reject) => {
            let count = 0;

            function addDate(key, data) {
                results[key] = data;
                count++;
                if (count === arr.length) {
                    resolve(results);
                }
            }

            for (let i = 0; i < arr.length; i++) {
                let current = arr[i];
                if (current instanceof MyPromise) {
                    current.then(
                        (value) => {
                            addDate(i, value);
                        },
                        (reason) => {
                            reject(reason);
                        }
                    );
                } else {
                    addDate(i, arr[i]);
                }
            }
        });
    }

    //实现resolve方法
    static resolve(value) {
        if (value instanceof MyPromise) {
            return value;
        } else {
            return new Promise((resolve, reject) => {
                resolve(value);
            });
        }
    }
}
